/*
 *		Player.cpp
 */

#include "Player.h"

// constructor - set's name and adds the mesh in correct scale into the scenemanager. --------------------------
Player::Player(string name, SceneManager *sceneMgr, char *meshfile, double scale, MooseFlag *flags, bool isP1)
{
	
	if (isP1)
	{
		keyLeft = OIS::KC_LEFT;
		keyRight = OIS::KC_RIGHT;		
		keyUp = OIS::KC_UP;
		keyDown = OIS::KC_DOWN;
	}
	else
	{
		keyLeft = OIS::KC_A;
		keyRight = OIS::KC_D;		
		keyUp = OIS::KC_W;
		keyDown = OIS::KC_S;
	}
	
	// set member variables
	this->name = name;
	this->score = 0;
	this->sceneMgr = sceneMgr;
	this->flags = flags;
	
	// Add a model, mesh
	Ogre::Entity* carEntity = sceneMgr->createEntity( name, meshfile );
	carEntity->setCastShadows(true);
	
	if (isP1)
		carEntity->setMaterialName("rod");
	else
		carEntity->setMaterialName("bla");
	
	if(carEntity->hasEdgeList())
		std::cout << "Har edgelist!" << std::endl;
	else
		std::cout << "Har inte edgelist!" << std::endl;
	
	node = sceneMgr->getRootSceneNode()->createChildSceneNode( name + "Node" );
	node->scale(Vector3(scale));
	node->attachObject(carEntity);
	carEntity->setCastShadows(true);
	
	gravity =  Vector3(0, 0.982, 0);
	atGround = false;
	
	pitchy = 0;
	pitchyback = 0;
	rolly = 0;
	rollyright = 0;
	
}

// place initializes translation and rotational variables. ----------------------------------------------------
void Player::place(Vector3 pos, Quaternion ori, Vector3 vel, Vector3 acc)
{
	do_acc = 0;
	do_rot = 0;
	
	this->rotation = Radian(0);
	this->position = pos;
	this->orientation = ori;
	this->velocity = vel;
	this->acceleration = acc;
	
	node->translate(position);
	
	raySceneQuery = sceneMgr->createRayQuery(Ogre::Ray(node->getPosition(), Vector3::NEGATIVE_UNIT_Y));
	raySceneQueryFront = sceneMgr->createRayQuery(Ogre::Ray(node->getPosition() + Vector3(0, 0, 50), Vector3::NEGATIVE_UNIT_Y));
	raySceneQueryBack = sceneMgr->createRayQuery(Ogre::Ray(node->getPosition() + Vector3(0, 0, -50), Vector3::NEGATIVE_UNIT_Y));
	raySceneQueryLeft = sceneMgr->createRayQuery(Ogre::Ray(node->getPosition() + Vector3(-20, 100, 0), Vector3::NEGATIVE_UNIT_Y));
	raySceneQueryRight = sceneMgr->createRayQuery(Ogre::Ray(node->getPosition() + Vector3(20, 100, 0), Vector3::NEGATIVE_UNIT_Y));	
}


// Set do_* variables according to keypress ---------------------------------------------------------------------
bool Player::keyPressed(const OIS::KeyEvent &e)
{
	if (e.key == keyLeft)
			do_rot = 1;
	else if (e.key == keyRight) 
			do_rot = -1;
	else if (e.key == keyUp) 
			do_acc = 3;
	else if (e.key == keyDown)
			do_acc = -2;
	
}
// 	We released a key, set its do_* to 0 ---------------------------------------------------------------------
bool Player::keyReleased(const OIS::KeyEvent &e)
{

		if (e.key == keyLeft || e.key == keyRight) 
			do_rot = 0;
		else if (e.key == keyUp || e.key == keyDown) 
			do_acc = 0;
}


// Check against ground and move SceneNode	---------------------------------------------------------------------
void Player::updateColl()
{
	//Skapar str√•larna
	
	static Ogre::Ray updateRay;
	static Ogre::Ray updateRayFront;
	static Ogre::Ray updateRayBack;
	static Ogre::Ray updateRayLeft;
	static Ogre::Ray updateRayRight;
	
	//S√§tter origin och direction f√∂r str√•larna
	
	updateRay.setOrigin(node->getPosition() + Vector3(0,30,0));
	updateRay.setDirection(Vector3::NEGATIVE_UNIT_Y);
	
	updateRayFront.setOrigin(node->getPosition() + node->getOrientation()*Vector3(0, 50, 20));
	updateRayFront.setDirection(Vector3::NEGATIVE_UNIT_Y);
	
	updateRayBack.setOrigin(node->getPosition() + node->getOrientation()*Vector3(0, 50, -20));
	updateRayBack.setDirection(Vector3::NEGATIVE_UNIT_Y);
	
	updateRayLeft.setOrigin(node->getPosition() + node->getOrientation()*Vector3(-20, 100, 0));
	updateRayLeft.setDirection(Vector3::NEGATIVE_UNIT_Y);
	
	updateRayRight.setOrigin(node->getPosition() + node->getOrientation()*Vector3(20, 100, 0));
	updateRayRight.setDirection(Vector3::NEGATIVE_UNIT_Y);
	
	//Skapar querys f√∂r str√•lar
	
	raySceneQuery->setRay(updateRay);
	raySceneQueryFront->setRay(updateRayFront);
	raySceneQueryBack->setRay(updateRayBack);
	raySceneQueryLeft->setRay(updateRayLeft);
	raySceneQueryRight->setRay(updateRayRight);
	
	//raySceneQuery->setWorldFragmentType(Ogre::SceneQuery::WFT_SINGLE_INTERSECTION);
	
	//Skapar iteratorer f√∂r fr√•gorna (f√∂ljer str√•len)
	
	Ogre::RaySceneQueryResult& qryResult = raySceneQuery->execute();
	Ogre::RaySceneQueryResult::iterator i = qryResult.begin();
	
	Ogre::RaySceneQueryResult& qryResultFront = raySceneQueryFront->execute();
	Ogre::RaySceneQueryResult::iterator j = qryResultFront.begin();
	
	Ogre::RaySceneQueryResult& qryResultBack = raySceneQueryBack->execute();
	Ogre::RaySceneQueryResult::iterator k = qryResultBack.begin();		
	
	Ogre::RaySceneQueryResult& qryResultLeft = raySceneQueryLeft->execute();
	Ogre::RaySceneQueryResult::iterator l = qryResultLeft.begin();
	
	Ogre::RaySceneQueryResult& qryResultRight = raySceneQueryRight->execute();
	Ogre::RaySceneQueryResult::iterator m = qryResultRight.begin();
	
	//Tar in resultaten fr√•n str√•len i mitten av bilen (justerar s√• bilen inte faller igenom terr√§ngen)
	
	if (i != qryResult.end() && i->worldFragment && Math::Abs(node->getPosition().y + 20 - i->worldFragment->singleIntersection.y) < 30/*&& i->distance < 10 && i->distance != 0*/)
	{		
		atGround = true;
		
		node->setPosition(node->getPosition().x, 
						  i->worldFragment->singleIntersection.y + 9, 
						  node->getPosition().z);
		
		/*
		 node->setPosition(node->getPosition().x, 
		 node->getPosition().y - i->distance + 10, 
		 node->getPosition().z);
		 */
		
		//y = i->worldFragment->singleIntersection.y;
	}
	else
	{
		atGround = false;
	}
	
	//Tar in resultat fr√•n str√•larna fram och back och v√§nster och h√∂ger
	
	if(j != qryResultFront.end() && j->worldFragment &&  atGround)
		pitchy = j->worldFragment->singleIntersection.y;
	if(k != qryResultBack.end() && k->worldFragment && atGround)
		pitchyback = k->worldFragment->singleIntersection.y;
	if(l != qryResultLeft.end() && l->worldFragment && atGround)
		rolly = l->worldFragment->singleIntersection.y;	
	if(m != qryResultRight.end() && m->worldFragment && atGround)
		rollyright = m->worldFragment->singleIntersection.y;
	
	// Roterar bilen s√• den ligger i 'fas' med marken
	if(!atGround)
	{
		pitchyback += 1;
		node->pitch(Ogre::Math::ATan((pitchyback - pitchy) * 0.005));
		node->roll(Ogre::Math::ATan((rollyright - rolly) * 0.025));
	}
	else
	{
		node->pitch(Ogre::Math::ATan((pitchyback - pitchy) * 0.025));
		node->roll(Ogre::Math::ATan((rollyright - rolly) * 0.025));
	}
	
	
	
}

// Update variables and move SceneNode	---------------------------------------------------------------------
void Player::update(Real timeSinceLastFrame)
{
	// Rotation
	if(atGround)
	{
		rotation +=Radian( do_rot * 1.5 * timeSinceLastFrame * 0.5);
	}
	orientation = Quaternion(rotation, Vector3::UNIT_Y);
	node->setOrientation(orientation);
	
	// Translation
	if(atGround)
	{		
		acceleration = do_acc * 2 * 0.9 * timeSinceLastFrame * Vector3(Math::Sin(rotation), 0, Math::Cos(rotation));
		acceleration += node->getOrientation()*Vector3(Ogre::Math::Tan((rolly - rollyright) * 0.025) * 0.982 * 0.01,0,Ogre::Math::Tan((pitchyback - pitchy) * 0.025) * 0.982 * 0.1);
	}
	else
	{
		acceleration = Vector3(0,0,0);
	}
	
	velocity += acceleration;
	velocity *= 0.99;	// friction
	position += velocity;
	node->translate(velocity);
	
	// gravity
	if(atGround)
		gravity.y = 0.982;
	else
		gravity.y += gravity.y * 2 * timeSinceLastFrame;
	
	
	node->translate(-gravity);
	
	// place and rotate according to plane..
	this->updateColl();
	
	flags->updateAnimation(timeSinceLastFrame);
	
	if(node->getPosition().y < -1000)
	{
		std::cout << name << " DIED!" << std::endl;
		std::cout << "Current score: " << --score << std::endl;
		
		this->acceleration = Vector3::ZERO;
		this->velocity = Ogre::Vector3::UNIT_Z;
		this->position.x = 1000;
		this->position.y = 500;
		this->position.z = 1000;
		this->node->setPosition(position);
	}

	
	if(Math::Abs(node->getPosition().x - flags->getPosition().x) < 100 && Math::Abs(node->getPosition().z - flags->getPosition().z) < 100)
	{	
		flags->updatePosition();
		std::cout << name << " SCORES!" << std::endl;
		std::cout << "Current score: " << ++score << std::endl;
		if (score == 10)
			std::cout << "CONGRATUALTIONS " << name << "!\n YOU HAVE WON THE RACbE TO TEN" << std::endl;

	}
}